﻿using System.Net;
using System.Runtime.InteropServices;

using BodaNetCommunications.Cores;
using BodaNetCommunications.ModbusComs.ModbusUtil;
using BodaNetCommunications.Utilities.Results;

namespace BodaNetCommunications.ModbusComs
{
    public class ModbusTcp : ModbusBase, ICommDevice
    {
        public ConnectionOptions Options { get; private set; }

        public bool IsConnected => _commUnit != null && _commUnit.IsConnected;

        /// <summary>
        /// 事务处理标识符: 消息戳，递增
        /// </summary>
        int _tid = 0;

        public ModbusTcp()
        {

        }


        public BodaResult Connect(ConnectionOptions connectionOptions)
        {
            BodaResult bodaResult = new BodaResult();
            Options = connectionOptions;

            if (string.IsNullOrEmpty(Options.Ip) || false == IPAddress.TryParse(Options.Ip, out _))
            {
                bodaResult.IsSuccess = false;
                bodaResult.Message = $"Ip[{Options.Ip}]为空或者格式不正确";
                return bodaResult;
            }

            if (Options.Port < 0 || Options.Port > 65535)
            {
                bodaResult.IsSuccess = false;
                bodaResult.Message = $"Port[{Options.Port}]不正确";
                return bodaResult;
            }

            if (IsConnected)
            {
                bodaResult.IsSuccess = true;
                bodaResult.Message = $"Modbus【{Options.Ip}:{Options.Port}】的连接已经在线，不需要重复连接";
                return bodaResult;
            }

            _commUnit = new CommUnitModbusTcp(Options);

            BodaResult<bool> result = _commUnit.Open(Options.ConnectTimeout);
            if (!result.IsSuccess) return result;

            return result;
        }

        public void Disconnect()
        {
            _commUnit?.Close();
        }

        public BodaResult<byte> Read(string address, ushort count)
        {
            BodaResult<byte> bodaResult = new BodaResult<byte>();
            bodaResult.IsSuccess = true;

            var resAnay = AnalysisAddress(address, out var fuc, out var startAddress);
            if (!resAnay)
            {
                bodaResult.IsSuccess = false;
                bodaResult.Message = $"地址错误:{address}";
                return bodaResult;
            }

            switch (fuc)
            {
                case 1:
                case 2:
                    bodaResult = ReadCoilsBytes(Options.SlaveId, fuc, startAddress, count);
                    break;
                case 3:
                case 4:
                    bodaResult = ReadRegisters<byte>(Options.SlaveId, address, count);
                    break;
                default:
                    break;
            }

            // bodaResult.DataBytes = SwitchEndianType(bodaResult.DataBytes);

            return bodaResult;
        }

        public BodaResult Write(string address, byte[] value)
        {
            BodaResult bodaResult = new BodaResult();
            bodaResult.IsSuccess = true;

            var resAnay = AnalysisAddress(address, out var fuc, out var startAddress);
            if (!resAnay)
            {
                bodaResult.IsSuccess = false;
                bodaResult.Message = $"地址错误:{address}";
                return bodaResult;
            }

            switch (fuc)
            {
                case 1:
                case 2:
                    List<bool> bools = new List<bool>();
                    bools.AddRange(value.Select(m => ((m & 0x01) == 0x01) ? true : false));
                    bodaResult = WriteCoils(Options.SlaveId, startAddress, bools);
                    break;
                case 3:
                case 4:
                    bodaResult = WriteRegisters<byte>(Options.SlaveId, startAddress, value.ToList());
                    break;
                default:
                    break;
            }

            return bodaResult;
        }

        protected override BodaResult<List<byte>> Read(byte slaveNum, byte funcCode, ushort startAddr, ushort count, ushort respLen)
        {
            // 一、组建请求报文
            List<byte> dataBytes = this.CreateReadPDU(slaveNum, funcCode, startAddr, count);
            // 二、拼接ADU头
            List<byte> headerBytes = new List<byte>();

            // 1. 事务处理标识符: 每次消息增加1
            _tid++;
            _tid %= 65536;
            // 获取高位
            headerBytes.Add((byte)(_tid / 256));
            // 获取地位
            headerBytes.Add((byte)(_tid % 256));

            // 2. 协议标识符pid: 0=Modbus协议
            headerBytes.Add(0x00);
            headerBytes.Add(0x00);

            // 3. 数据长度len（大端模式）
            headerBytes.Add((byte)(dataBytes.Count / 256));
            headerBytes.Add((byte)(dataBytes.Count % 256));

            // 4. 数据 = 数据地址 + 数据长度
            headerBytes.AddRange(dataBytes);


            // 三、打开/检查通信组件的状态（如果未连接，则重新连接）
            //BodaResult<bool> connectState = this._commUnit.Open(100);
            //if (connectState.IsSuccess)
            //{
            // 四、发送请求报文
            BodaResult<byte> resp = this._commUnit.SendAndReceive(
                headerBytes, // 发送的请求报文 
                0, // 正常响应字节
                0); // 异常响应报文长度
            if (!resp.IsSuccess)
            {
                return BodaResult.CreateFailedResult<List<byte>>(resp.Message);
            }

            // 五、将Header部分移除
            resp.Datas.RemoveRange(0, 6);

            // 六、检查异常报文
            if (resp.Datas[1] > 0x80)
            {
                byte errorCode = resp.Datas[2];
                return BodaResult.CreateFailedResult<List<byte>>(ModbusErrors.Errors[errorCode]);
            }

            // 七、解析
            List<byte> datas = resp.Datas.GetRange(3, resp.Datas.Count - 3);
            return BodaResult.CreateSuccessResult(datas);
            //}
            //return BodaResult.CreateFailedResult<List<byte>>(connectState.Message);
        }

        protected override BodaResult<bool> Write(List<byte> bytes)
        {
            BodaResult<bool> result = BodaResult.CreateSuccessResult(true);

            // 二、拼接ADU头
            List<byte> headerBytes = new List<byte>();
            _tid++;
            _tid %= 65536;
            headerBytes.Add((byte)(_tid / 256));
            headerBytes.Add((byte)(_tid % 256));
            // pid
            headerBytes.Add(0x00);
            headerBytes.Add(0x00);
            // len
            headerBytes.Add((byte)(bytes.Count / 256));
            headerBytes.Add((byte)(bytes.Count % 256));

            headerBytes.AddRange(bytes);

            // 三、打开/检查通信组件的状态
            BodaResult<bool> connectState = this._commUnit.Open(100);
            if (!connectState.IsSuccess)
            {
                result.IsSuccess = false;
                result.Message = connectState.Message;
                return result;
            }

            // 四、发送请求报文
            BodaResult<byte> resp = this._commUnit.SendAndReceive(
                headerBytes, // 发送的请求报文 
                0,  // 正常返回的长度
                0); // 异常响应报文长度
            if (!resp.IsSuccess)
            {
                result.IsSuccess = false;
                result.Message = resp.Message;
                return result;
            }

            // 五、将Header部分移除
            resp.Datas.RemoveRange(0, 6);

            // 六、检查异常报文
            if (resp.Datas[1] > 0x80)
            {
                byte errorCode = resp.Datas[2];
                result.IsSuccess = false;
                result.Message = ModbusErrors.Errors[errorCode];
                return result;
            }

            return result;
        }

        // 由业务层面
        public void ReadRegistersAsync<T>(byte slaveNum, byte funcCode, ushort startAddr, ushort count,
            Action<BodaResult<T>> callbackt)
        {
            BodaResult<T> result = new BodaResult<T>();
            int len = Marshal.SizeOf(typeof(T));
            // 一、组建请求报文
            List<byte> dataBytes = this.CreateReadPDU(slaveNum, funcCode, startAddr, (ushort)(count * len / 2));
            // 二、拼接ADU头
            List<byte> headerBytes = new List<byte>();
            _tid++;
            _tid %= 65536;
            headerBytes.Add((byte)(_tid / 256));
            headerBytes.Add((byte)(_tid % 256));
            // pid
            headerBytes.Add(0x00);
            headerBytes.Add(0x00);
            // len
            headerBytes.Add((byte)(dataBytes.Count / 256));
            headerBytes.Add((byte)(dataBytes.Count % 256));

            headerBytes.AddRange(dataBytes);


            BodaResult<bool> connectState = this._commUnit.Open(100);
            if (connectState.IsSuccess)
            {
                (this._commUnit as CommUnitModbusTcp).SendAsync(
                    headerBytes, resp =>
                    {
                        // 通信单元异步返回的结果
                        // 这个结果里可以拿到返回的报文字节
                        if (!resp.IsSuccess)
                            throw new Exception(resp.Message);

                        // 五、将Header部分移除
                        resp.Datas.RemoveRange(0, 6);

                        // 六、检查异常报文
                        if (resp.Datas[1] > 0x80)
                        {
                            byte errorCode = resp.Datas[2];
                            throw new Exception(ModbusErrors.Errors[errorCode]);
                        }
                        // 七、解析
                        List<byte> datas = resp.Datas.GetRange(3, resp.Datas.Count - 3);
                        result.DataBytes.AddRange(datas);

                        result.Datas.AddRange(this.ReadValuesByBytes<T>(datas));
                        callbackt?.Invoke(result);
                    });
            }
            else
            {
                result.IsSuccess = false;
                result.Message = connectState.Message;
                callbackt?.Invoke(result);
            }
        }


        public BodaResult SendMsgc(byte[] bytes, int timeout = 1500)
        {
            throw new NotImplementedException();
        }

        public BodaResult<byte> ReceiveMsg(int timeout = 2000, int bytesLen = 1024)
        {
            throw new NotImplementedException();
        }
    }
}
